#include <iostream>
#include <fstream>
#include <vector>
#include <jsoncpp/json/json.h>
#include "Function.h"
#include "Spline.h"

using namespace std;

class fun2 : public Function {
public:
    double operator()(const double& x) const {
      return 1.0 / (1.0 + x * x);
    }
    double get_diff(const double& x) const {
      return -2.0 * x * (*this)(x) * (*this)(x);
    }
    double get_secdiff(const double& x) const {
      return (6 * x * x - 2.0) * (*this)(x) * (*this)(x) * (*this)(x);
    }
}f;

int main() {

    ifstream ifs("./input/C_input.json");
    ofstream ofs1, ofs2;
    ofs1.open("./output/C_output.txt");
    ofs2.open("./output/D_output.txt");

    Json::Reader reader;
    Json::Value obj;
    reader.parse(ifs, obj);
    
    //读取条件
    vector<double> knots1, knots2, knots_error;
    double LeftBound = obj["C_LeftBound"].asDouble();
    double RightBound = obj["C_RightBound"].asDouble();
    for (int i = 0; i < obj["C_Knots1"].size(); i++) {
        knots1.push_back(obj["C_Knots1"][i].asDouble());
    }
    for (int i = 0; i < obj["C_Knots2"].size(); i++) {
        knots2.push_back(obj["C_Knots2"][i].asDouble());
    }
    for (int i = 0; i < obj["D_sites"].size(); i++) {
        knots_error.push_back(obj["D_sites"][i].asDouble());
    }

    //quadatic b-spline
    vector<double> values2;
    for (int i = 0; i < knots2.size(); i++) {
        values2.push_back(f(knots2[i]));
    }
    double cond_left2 = f(knots1[0]);
    double cond_right2 = f(knots1[knots1.size() - 1]);
    Bspline<2> bspline_qua(knots1, values2, cond_left2, cond_right2);

    //cubic b-spline
    vector<double> values1;
    for (int i = 0; i < knots1.size(); i++) {
        values1.push_back(f(knots1[i]));
    }
    double cond_left1 = f.get_diff(knots1[0]);
    double cond_right1 = f.get_diff(knots1[knots1.size() - 1]);
    Bspline<3, Complete> bspline_cub(knots1, values1, cond_left1, cond_right1);


    //绘图点
    double PointsNum = 1001;
    vector<double> points;
    ofs1 << "Cardinal B-Spline Interpolation: " << endl;
    ofs1 << "points: " << endl;
    for (int j = 0; j < PointsNum; j++) {
        points.push_back(LeftBound + j * (RightBound - LeftBound) / (PointsNum - 1));
	    ofs1 << points[j] << " ";
    }
    ofs1 << endl;
    ofs1 << "f(x): " << endl;
    for (int j = 0; j < PointsNum; j++) {
	    ofs1 << f(points[j]) << " ";
    }
    ofs1 << endl;
	ofs1 << "quadratic cardinal b-spline: " << endl;
    for (int j = 0; j < PointsNum; j++) {
        ofs1 << bspline_qua(points[j]) << " ";
    }
	ofs1 << endl;
    ofs1 << "cubic cardinal b-spline: " << endl;
    for (int j = 0; j < PointsNum; j++) {
        ofs1 << bspline_cub(points[j]) << " ";
    }
    ofs1 << endl;  
    ofs1 << endl;
    
    //计算误差
    ofs2 << "error points: " << endl;
    for (int i = 0; i < knots_error.size(); i++) {
        ofs2 << knots_error[i] << " ";
    }
    ofs2 << endl;
    ofs2 << "quadratic cardinal b-spline: " << endl;
    for (int i = 0; i < knots_error.size(); i++) {
        ofs2 << abs(f(knots_error[i]) - bspline_qua(knots_error[i])) << " ";
    }
    ofs2 << endl;
    ofs2 << "cubic cardinal b-spline: " << endl;
    for (int i = 0; i < knots_error.size(); i++) {
        ofs2 << abs(f(knots_error[i]) - bspline_cub(knots_error[i])) << " ";
    }
    ofs2 << endl;

    ofs1.close();
    ofs2.close();

    return 0;
}
